![Amplify Gen2はユーザ名でログイン可能です](https://devio2023-media.developers.io/wp-content/uploads/2023/08/aws-amplify.png)
Amplify Gen2はユーザ名でログイン可能です
NTT東日本の中村です。
Amplify Gen1では、認証のログインにユーザ名を指定することができます、 Amplify Gen2では、ユーザ名を指定できないように見えますが、CDKを使えば実現できるようです。
概要
AmplifyのGen1,Gen2のどちらも、ユーザ認証のシステムに、内部でAmazon Cognitoを使用しています。
Amazon Cognitoは、認証のオプションにユーザ名、Eメール、電話番号を選択することができます。 マネジメントコンソールからAmazon Cognitoを作成すると、選択肢からユーザ名を選ぶことができます。
Amplify Gen1でも、amplify add Authを実行した時、選択肢にユーザ名(Username)を選ぶことができます。
Amplify Gen2は、auth/resource.tsの中で認証方法を定義しますが、emailとphoneのみが許可されており、ユーザ名を選ぶことができません。 Cognitoでは選べるが、Amplify Gen2では意図的にユーザ名でのログインが隠されている事が分かります。
ただし、移行ガイドを見ると「CDKで実現可能」と書かれています。 何故隠されているのか?と、どのように実現出来るのか?を調査しました。
調査してみた
ユーザ名の取り扱いについて、こちらで書かれています。
何故隠されているのか
Amazon Cognito では、ユーザー名は不変です。つまり、最初のサインアップ後は、ユーザーはユーザー名を変更できません。一部のアプリケーションでは、これは望ましくない場合があり、その場合はエイリアス属性を使用することをお勧めします。エイリアス属性を使用すると、不変のユーザー名に加えて、変更可能な「優先ユーザー名」を定義できます。
Username属性は不変であり、一度設定すると変更できません。この値をログインに使用すると、リスクが発生する場合がある、という判断を行っているようです。
ただし、Gen1からGen2へのマイグレーションを行う場合、既存ではユーザ名でログインを行っていたシステムも多く、ユーザ名でどうしてもログインしたい、というニーズは存在します。
どの様に実現できるのか
ドキュメントを見ると、CDKのオーバーライドで、usernameAttributes属性からEメール、電話番号を取り除き、空配列で定義することで、ユーザ名でログインができるようです。
import { defineBackend } from "@aws-amplify/backend"; import { auth } from "./auth/resource.js"; import { data } from "./data/resource.js"; const backend = defineBackend({ auth, data, }); const { cfnUserPool } = backend.auth.resources.cfnResources; // an empty array denotes "email" and "phone_number" cannot be used as a username cfnUserPool.usernameAttributes = [];
ちなみに、usernameAttributesに、preferred_username等の他のユーザー属性を設定することはできませんでした。
usernameAttributes' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [phone_number, email]]
適当なログイン画面を用意します。
"use client"; import { Authenticator } from '@aws-amplify/ui-react' import { Amplify } from "aws-amplify"; import outputs from "@/amplify_outputs.json"; import '@aws-amplify/ui-react/styles.css' Amplify.configure(outputs); export default function App() { return ( <Authenticator> {({ signOut, user }) => ( <main> login successful </main>)} </Authenticator> ); }
ログインに成功しました。
ログイン属性にユーザ名が使用されていることが分かります。
上の画像ではエイリアス属性と書かれていますが、実際には不変のUsername属性が使われており、変更することができません。
aws cognito-idp admin-get-user --user-pool-id ap-northeast-1_hogehoge --username test { "Username": "test", "UserAttributes": [ { "Name": "email", "Value": "hoge@hoge.jp" }, { "Name": "email_verified", "Value": "true" }, { "Name": "sub", "Value": "d7748af8-a081-70c7-0671-2b11432e3b71" } ], "UserCreateDate": "2024-06-26T06:48:48.017000+00:00", "UserLastModifiedDate": "2024-06-26T06:49:30.916000+00:00", "Enabled": true, "UserStatus": "CONFIRMED" }
ユーザ名で問題なくログインできることも確認できました。
まとめ
Gen2では、ユーザ名とパスワードでのログインを勧めておらず、エイリアス属性のEmailや電話番号を勧めています。ユーザ名は、一度設定すると変更ができない為です。
しかしながら、CDKからオーバーライドを行うことで、ユーザ名でのログインは可能なので、マイグレーション等で必須の対応がある時は検討できる選択肢だと思います。